Completed
Push — master ( d25395...d83c14 )
by Jan
15s queued 14s
created

FrameHeader.ts ➔ createFromBuffer   A

Complexity

Conditions 4

Size

Total Lines 18
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 15
dl 0
loc 18
rs 9.65
c 0
b 0
f 0
cc 4
1
import * as ID3Util from './ID3Util'
2
import {
3
    FRAME_IDENTIFIERS,
4
    FRAME_ALIASES }
5
from "./definitions/FrameIdentifiers"
6
7
export type Flags = {
8
    tagAlterPreservation?: boolean
9
    fileAlterPreservation?: boolean
10
    readOnly?: boolean
11
    compression?: boolean
12
    encryption?: boolean
13
    groupingIdentity?: boolean
14
    unsynchronisation?: boolean
15
    dataLengthIndicator?: boolean
16
}
17
18
export class FrameHeader {
19
    identifier: string
20
    bodySize: number
21
    flags: Flags
22
23
    constructor(identifier: string, bodySize: number, flags: Flags = {}) {
24
        this.identifier = identifier
25
        this.bodySize = bodySize
26
        this.flags = flags
27
    }
28
29
    static createFromBuffer = createFromBuffer
30
31
    getBuffer() {
32
        const buffer = Buffer.alloc(10)
33
        buffer.write(this.identifier, 0)
34
        buffer.writeUInt32BE(this.bodySize, 4)
35
        return buffer
36
    }
37
38
}
39
40
function createFromBuffer(headerBuffer: Buffer, version: number) {
41
    const identifierSize = version === 2 ? 3 : 4
42
    let identifier = headerBuffer.toString('utf8', 0, identifierSize)
43
    const frameSize = getBodySize(headerBuffer, version)
44
    const flags = extractFlags(headerBuffer[8], headerBuffer[9], version)
45
46
    // Try to convert identifier for older versions
47
    if (version === 2) {
48
        const aliasesV2: Record<string, string> = FRAME_ALIASES.v2
49
        const alias = aliasesV2[identifier]
50
        if (alias) {
51
            const identifiers: Record<string, string> = FRAME_IDENTIFIERS.v34
52
            identifier = identifiers[alias]
53
        }
54
    }
55
56
    return new FrameHeader(identifier, frameSize, flags)
57
}
58
59
function extractFlags(
60
    statusFlag: number,
61
    encodingFlag: number,
62
    version: number
63
) {
64
    if (version === 3) {
65
        return {
66
            tagAlterPreservation: !!(statusFlag & 128),
67
            fileAlterPreservation: !!(statusFlag & 64),
68
            readOnly: !!(statusFlag & 32),
69
            compression: !!(encodingFlag & 128),
70
            encryption: !!(encodingFlag & 64),
71
            groupingIdentity: !!(encodingFlag & 32),
72
            dataLengthIndicator: !!(encodingFlag & 128)
73
        }
74
    }
75
    if (version === 4) {
76
        return {
77
            tagAlterPreservation: !!(statusFlag & 64),
78
            fileAlterPreservation: !!(statusFlag & 32),
79
            readOnly: !!(statusFlag & 16),
80
            groupingIdentity: !!(encodingFlag & 64),
81
            compression: !!(encodingFlag & 8),
82
            encryption: !!(encodingFlag & 4),
83
            unsynchronisation: !!(encodingFlag & 2),
84
            dataLengthIndicator: !!(encodingFlag & 1)
85
        }
86
    }
87
    return {}
88
}
89
90
export function getHeaderSize(version: number) {
91
    return version === 2 ? 6 : 10
92
}
93
94
function getBodySize(headerBuffer: Buffer, version: number) {
95
    const isEncoded = version === 4
96
97
    const bytes = version === 2 ?
98
        [headerBuffer[3], headerBuffer[4], headerBuffer[5]] :
99
        [headerBuffer[4], headerBuffer[5], headerBuffer[6], headerBuffer[7]]
100
101
    if (isEncoded) {
102
        return ID3Util.decodeSize(Buffer.from(bytes))
103
    }
104
    return Buffer.from(bytes).readUIntBE(0, bytes.length)
105
}
106
107
export function getFrameSize(buffer: Buffer, version: number) {
108
    return getHeaderSize(version) + getBodySize(buffer, version)
109
}
110